using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;

namespace Wrath.CodeBox
{
    public class LanguageParser
    {
        public readonly Language Language = new Language();

        private string source;
        private string currentPass;
        private Stack<Token> tokens = new Stack<Token>();

        public bool IsFinished
        {
            get { return (currentPass == "" && tokens.Count == 0); }
        }

        public Token LexNext()
        {
            Token tok;
            if (tokens.Count > 0)
            {
                return tokens.Pop();
            }

            foreach (KeyValuePair<string, TokenClass> kvp in Language.TokenClasses)
            {
                TokenClass tc = kvp.Value;
                MatchCollection col = tc.Match.Matches(currentPass);

                if (col.Count > 0)
                {
                    tok = new Token(tc.Name, col[0].ToString());
                    currentPass = currentPass.Substring(col[0].Length + 1);

                    // turn identifiers into keywords
                    if (tok.Type == "identifier")
                    {
                        if (Language.IsCaseSensitive)
                        {
                            // case-sensitive matching
                            if (Language.Keywords.ContainsKey(tok.Value))
                            {
                                tok.Type = "keyword";
                            }
                        }
                        else
                        {
                            // case in-sensitive matching
                            if (Language.Keywords.ContainsKey(tok.Value.ToLower()))
                            {
                                tok.Type = "keyword";

                                // set the token value to reflect the preferred case
                                tok.Value = Language.Keywords[tok.Value.ToLower()];
                            }
                        }
                    }
           
                    // done
                    return tok;
                }
            }

            // failed to find anything to match
            tok = new Token("UNRECOGNISED", currentPass[0].ToString());
            currentPass = currentPass.Substring(1);

            return tok;
        }

        public void Rewind()
        {
            currentPass = source;
            tokens.Clear();
            tokens.TrimExcess();
        }

        public string Source
        {
            set 
            {
                source = value;
                Rewind();
            }
        }

        public void UnLex(Token Item)
        {
            tokens.Push(Item);
        }

        public LanguageParser(string FilePath)
        {
            StreamReader sr;
            string def;

            // load the language definition
            sr = new StreamReader(FilePath);
            def = sr.ReadToEnd();
            sr.Close();

            // create a language object
            Language = new Language(def);
        }

        public LanguageParser()
        {
        }
    }
}
